package com.qianxun.voice;

import com.qianxun.voice.enums.SpeedEnum;
import com.qianxun.voice.enums.ToneEnum;
import org.apache.commons.io.IOUtils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;

/**
 * @author: huwei
 * @date: 2020/8/6 9:31
 * @version: 1.0.0
 */
public class ZhVoiceUtil {

    /**
     * 将指定的文本转化为音频文件
     * @param text 转化文本
     * @return 返回音频文件的字节数组
     * @throws IOException
     */
    public static byte[] toVoice(String text) throws IOException {
        ByteArrayOutputStream os = new ByteArrayOutputStream();

        char[] chars = text.toCharArray();
        //逐字获取音频内容
        for(int i = 0 ;i < chars.length ;++i){
            InputStream inputStream = Inner.findAndGetTextVoice(chars[i]);
            if(inputStream == null){
                continue;
            }
            //用于判断句子是否断句和结束
            InputStream nextInputStream = null;
            if(i + 1 < chars.length){
                nextInputStream = Inner.findAndGetTextVoice(chars[i+ 1]);
            }

            //读取音频内容
            byte[] buf = new byte[inputStream.available()];
            IOUtils.read(inputStream ,buf);
            inputStream.close();

            //句子连贯处理
            byte[] t = sentenceProcess(buf ,nextInputStream ,SpeedEnum.ONE);

            //写入结果集
            os.write(t);
        }
        byte[] res = os.toByteArray();
        os.close();
        return res;
    }

    /**
     * 单字合成句子，必须要做连贯性处理，否则合成的音频句子将不连贯；
     *
     * 当前这种方式有大问题：：某些字发音比较轻，则再合并的句子中，将听不到其发音；即便对该字不做音频截取，一样如此！！！ 待解决
     *
     * @param buf 当前字的音频字节内容
     * @param next 下一个字的输入流
     * @param speedEnum 语速
     * @return
     */
    private static byte[] sentenceProcess(byte[] buf ,InputStream next ,SpeedEnum speedEnum){
        int minLength = voiceRealContentEndIndex(buf);
        int length;
        if(next == null){
            //下一个发音为空，这种情况一般为句子断句，或者该句子以结束，则当前字的发音可以拖长一些；
            length = buf.length;
        }else if(speedEnum == null){
           length = minLength;
        }else {
            length = minLength + speedEnum.getSpeed() * 100;
        }
        length = length > buf.length ? buf.length : length;
        return Arrays.copyOf(buf ,length);
    }

    private static int voiceRealContentEndIndex(byte[] voiceByte){
        //该标识暂定标记为音频的结束标志；不精准的理由是，对比几个单字的音频的字节数据，发现每一个单字音频中都有该数据；
        String tails = "76,65,77,69,51,46,57,57,46,53";
        String[] s = tails.split(",");
        int index = voiceByte.length;
        for(int i = 0 ;i < voiceByte.length ;++i){
            if(s[0].equals(voiceByte[i] + "" )){
                boolean b = true;
                for(int j = 1; j< s.length;++j){
                    if(!s[j].equals(voiceByte[i+ j] + "" )){
                        b = false;
                        break;
                    }
                }
                if(b){
                    index = i - 1;
                    break;
                }
            }
        }
        return index;
    }

    private static final class Inner{
        /**
         * 文字库，根路径
         */
        static final String TEXT_ROOT_PATH = "zh_text";
        /**
         * 语言文件目录名
         */
        static final String VOICE_DIR_NAME = "voice";
        /**
         * 语言文件后缀名
         */
        static final String VOICE_FILE_SUFFIX = "5.mp3";


        static InputStream findAndGetTextVoice(char text){
            String path = buildAndGetTextPath(text  ,ToneEnum.ZERO);
            return Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
        }

        static String buildAndGetTextPath(char text ,ToneEnum toneEnum){
            //TODO 暂时不对声调做处理
            StringBuffer stringBuffer = new StringBuffer(TEXT_ROOT_PATH);
            stringBuffer.append(File.separator).append(text).append(File.separator)
                    .append(VOICE_DIR_NAME).append(File.separator).append(VOICE_FILE_SUFFIX);
            return stringBuffer.toString();
        }
    }
}
